package com.hanfu.ucenter.web.web.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.hanfu.ucenter.web.constants.UcenterConstant;
import com.hanfu.ucenter.web.exception.ErrorCode;
import com.hanfu.ucenter.web.exception.UCenterException;
import com.hanfu.ucenter.web.web.param.UserDto;
import com.hanfu.ucenter.web.web.util.BeanValidators;
import com.hanfu.ucenter.web.web.util.JwtHelper;
import com.hanfu.ucenter.web.web.vo.ClientResp;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import javax.validation.Validator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by dufei on 19/9/18.
 */
public  abstract  class UCenterBaseController<P, R> {

    protected Logger logger = LoggerFactory.getLogger(UCenterBaseController.class);

    @Autowired
    protected Validator validator;

    @RequestMapping(method = RequestMethod.POST, value = "", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public ClientResp<R> request(@RequestBody(required = false)  P req, HttpServletRequest httpServletRequest, @RequestHeader(UcenterConstant.TOKEN_AUTHORIZATION) String token) throws UCenterException {

        try {
            if (null != req) {
                BeanValidators.validateWithException(validator, req);
            }
        }catch (ConstraintViolationException e){
            List<String> cons = extractMessage(e.getConstraintViolations());
            return new ClientResp<>(ErrorCode.PARAMS_ERROR.getCode() , StringUtils.join(cons, ","));
            //throw new  UCenterException(ErrorCode.PARAMS_ERROR.getCode() , StringUtils.join(cons, ","));
        }
        String json = JSON.toJSONString(req);
        if (isContainIllegalChars(json)){
            return new ClientResp<>(ErrorCode.PARAMS_ERROR.getCode() , "输入包含非法字符，请检查输入");
            //return new  UCenterException(ErrorCode.PARAMS_ERROR.getCode() , "输入包含非法字符，请检查输入");
        }
        Claims claims =  JwtHelper.parseJWT(token,UcenterConstant.SECRET_KEY);
        Map<String,String> useMap = (Map<String, String>) claims.get("userinfo");
        logger.info("user id is {}",useMap.get("id"));
        UserDto userInfo = new UserDto();
        userInfo.setId(Long.valueOf(String.valueOf(useMap.get("id"))));
        logger.info("user Info is {}",userInfo);
      try {
            R res = doService(req,httpServletRequest,userInfo);
            return new ClientResp<>(res);
        }catch (UCenterException e){
            logger.error("{}", e);
            logger.error("SailClientException: errorCode:{},errorMsg:{}",e.getCode(),e.getMsg());
            return new ClientResp<>(e.getCode(),e.getMsg());
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            return new ClientResp<>(ErrorCode.BUSY.getCode() , ErrorCode.BUSY.getTip());
        }
    }

    /**
     * 默认验证登录s，子类可以重写此方法以关闭登录验证
     *
     * @return
     */
    protected abstract R doService(P req,HttpServletRequest httpServletRequest,UserDto userInfo) throws UCenterException;

    /**
     * 辅助方法, 转换Set<ConstraintViolation>为List<message>
     */
    protected static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
        List<String> errorMessages = Lists.newArrayList();
        for (ConstraintViolation violation : constraintViolations) {
            errorMessages.add( violation.getMessage());
        }
        return errorMessages;
    }

    /**
     * @param value v
     * @return boolean
     */
    public static boolean isContainIllegalChars(String value){
        if (StringUtils.isBlank(value))
            return false;
        if (value.contains("<") || value.contains(">"))
            return true;
        return false;
    }

}
